import Events from "./Events";
import { setViewer, getViewer, removeViewer, setMap, removeMap } from './ViewerCache'
import { uuid, formatPostionForEvent, getCurrentExtent, getCenterPosition } from './util';
import RightMenu from './RightMenu';
const Cesium = window.Cesium;

// 一张空的1像素图片，用来取消掉 Cesium 的默认 401 请求
var defaultImage = ''

/**
 * 实例化地图对象
 *
 * @class simpleMap
 * @param {HTMLElement} HTMLElement 地图容器（HTML元素）
 * @param {Object} [options={}] 地图参数（可选）
 * @example 
 * // 默认参数
 * new simpleMap(document.getElementById('map'));
 * // 带地图参数
 * new simpleMap(document.getElementById('map'),{
 *      mapOptions: {
 *          senceMode: "2D", // 初始化时，以2D模式进行渲染
 *      },
 * });
 * @extends {Events} 继承类 事件委托方法
 */
class simpleMap extends Events {
    constructor(HTMLElement, options = {}) {
        super();
        this.simpleId = uuid();
        this.TypeName = 'simpleMap';
        this.mapOptions = options.mapOptions || {};
        this.terrainUrl = options.terrainUrl;
        this.imageryProvidersOptions = options.imageryProviders;
        this.DataSource = [];
        let viewer = new Cesium.Viewer(HTMLElement, {
            imageryProvider: new Cesium.SingleTileImageryProvider({
                url: defaultImage,
                rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
            }),
            // useDefaultRenderLoop: false,
            animation: this.mapOptions.animation || false,
            baseLayerPicker: this.mapOptions.baseLayerPicker || false,
            fullscreenButton: this.mapOptions.fullscreenButton || false,
            fullscreenElement: document.body,
            geocoder: this.mapOptions.geocoder || false,
            homeButton: this.mapOptions.homeButton || false,
            infoBox: this.mapOptions.infoBox || false,
            navigationHelpButton: this.mapOptions.navigationHelpButton || false,
            scene3DOnly: this.mapOptions.scene3DOnly || false,
            sceneModePicker: this.mapOptions.sceneModePicker || false,
            timeline: this.mapOptions.timeline || false,
            terrainExaggeration: 1.2,
            // mapMode2D: Cesium.MapMode2D.ROTATE,
            mapProjection: new Cesium.WebMercatorProjection(),
            orderIndependentTranslucency: false,
            contextOptions: {
                webgl: {
                    alpha: true,
                    depth: true,
                    stencil: true,
                    antialias: true,
                    premultipliedAlpha: true,
                    //通过canvas.toDataURL()实现截图需要将该项设置为true
                    preserveDrawingBuffer: true,
                    // failIfMajorPerformanceCaveat: true
                }
            }
            // imageryProvider: false,
            // baseLayerPicker: false,
            // timeline: false,
            // infoBox: false,
            // navigationHelpButton: false,
            // fullscreenButton: false,
            // animation: false,
            // geocoder: false,
            // homeButton: false,
            // sceneModePicker: false
        });

        viewer.scene.globe.enableLighting = false;
        viewer.shadows = false;

        // let start = Cesium.JulianDate.now();
        // let stop = Cesium.JulianDate.addDays(
        //     start,
        //     360,
        //     new Cesium.JulianDate()
        // );
        // viewer.clock.startTime = start.clone();
        // viewer.clock.stopTime = stop.clone();
        // viewer.clock.currentTime = start.clone();
        // viewer.clock.multiplier = 1;
        // viewer.clock.shouldAnimate = true;

        // 深度检测
        // viewer.scene.globe.depthTestAgainstTerrain = false;
        viewer.scene.globe.depthTestAgainstTerrain = true
        if (this.terrainUrl) {
            let terrainProvider = null;
            terrainProvider = new Cesium.CesiumTerrainProvider({
                url: this.terrainUrl,
                requestWaterMask: true, // 开启法向量
                requestVertexNormals: true, // 开启水面
            });
            viewer.terrainProvider = terrainProvider;
        }

        viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
        viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);

        // 去掉版权信息
        viewer._cesiumWidget._creditContainer.style.display = "none";

        this.ProviderCatch = [];
        setViewer(this.simpleId, viewer);
        setMap(this.simpleId, this);
        this._initInputAction();

        /**
         * 地图显示模式
         * @example 
         * map.SenceMode = '2D' // 切换为2D 显示模式
         * map.SenceMode = '3D' // 切换为3D 显示模式
         * @memberof simpleMap
         */
        this.SenceMode = this.mapOptions.senceMode || '2D';

        /**
         * 右键菜单对象
         * @memberof simpleMap
         */
        this.RightMenu = new RightMenu(this);
    }
    set SenceMode(type) {
        if (['2D', '3D'].includes(type)) {
            this._SenceMode = type;
            var viewer = getViewer(this.simpleId);
            viewer.scene.mode = Cesium.SceneMode['SCENE' + type];
            this.run('changeSceneMode', type);
        }
    }
    get SenceMode() {
        return this._SenceMode;
    }
    _initInputAction() {
        let viewer = getViewer(this.simpleId);
        let EventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
        // 鼠标移动事件绑定方法
        EventHandler.setInputAction((event) => {
            let _event = formatPostionForEvent(this.simpleId, event);
            _event && this.run('MouseMove', _event, event);
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

        EventHandler.setInputAction((event) => {
            let isStop = false;
            let stop = () => isStop = true;

            let pickEntity = viewer.scene.pick(event.position, 10, 10);
            pickEntity && this.run('PickEntity', pickEntity, stop);

            let pickArrayEntity = viewer.scene.drillPick(event.position, null, 10, 10);
            pickArrayEntity.length && this.run('PickMultiEntity', pickArrayEntity, stop);

            if (!isStop) {
                let _event = formatPostionForEvent(this.simpleId, event);
                _event && this.run('Click', _event);
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        EventHandler.setInputAction((event) => {
            let isStop = false;
            let stop = () => isStop = true;

            let pickEntity = viewer.scene.pick(event.position, 10, 10);
            pickEntity && this.run('RightPickEntity', pickEntity, stop);

            let pickArrayEntity = viewer.scene.drillPick(event.position, null, 10, 10);
            pickArrayEntity.length && this.run('RightPickMultiEntity', pickArrayEntity, stop);

            if (!isStop) {
                let _event = formatPostionForEvent(this.simpleId, event);
                _event && this.run('RightClick', _event);
            }
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

        EventHandler.setInputAction((event) => {
            let isStop = false;
            let stop = () => isStop = true;

            let pickEntity = viewer.scene.pick(event.position);
            pickEntity && this.run('DBLClickPickEntity', pickEntity);

            let pickArrayEntity = viewer.scene.drillPick(event.position, null, 10, 10);
            pickArrayEntity.length && this.run('DBLClickPickMultiEntity', pickArrayEntity, stop);

            if (!isStop) {
                let _event = formatPostionForEvent(this.simpleId, event);
                _event && this.run('DBLClick', _event);
            }
        }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

        this._getCurrentExtent = function (zoom) {
            let PostionView = getCurrentExtent(this.simpleId);
            PostionView.zoom = zoom
            this.run('MapMove', PostionView);
        }

        this._onMoveendMap = () => {
            let height = Math.ceil(viewer.camera.positionCartographic.height);
            let zoom = this.heightToZoom(height);
            this._getCurrentExtent(zoom);
        }
        viewer.camera.moveEnd.addEventListener(this._onMoveendMap);

        // 监听动画方法
        this._TickEvent = (clock) => {
            this.run('Tick', clock);
        }
        viewer.clock.onTick.addEventListener(this._TickEvent);
    }
    heightToZoom(height) {
        var A = 40487.57;
        var B = 0.00007096758;
        var C = 91610.74;
        var D = -40467.74;
        return Math.round(D + (A - D) / (1 + Math.pow(height / C, B)));
    }
    /**
     * 添加地图图源
     *
     * @param {Array} MapOptions 添加图源列表
     * @memberof simpleMap
     * @example
     * Map.addproviders([{
     *     "type": "TD", // 图源类型：TD(天地图)/ARCGIS
     *     "name": "标注信息", // 图源名称
     *     "layerType": "background", // 图源显示类型 background (背景图) / mark (标注)
     *     "url": "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", // 地图地址
     *     "default": false // 是否默认开启（多个true时，加载最后一个）
     * }, {
     * // 其他图层信息
     * ...
     * }])
     */
    addProviders(MapOptions) {
        let viewer = getViewer(this.simpleId);
        viewer.imageryLayers.removeAll();
        if (!MapOptions || MapOptions.length <= 0) {
            throw new Error("必需提供至少一个地图服务提供者！");
        }

        let BackgroundProvider = null;
        let MarkProvider = null;

        for (let i = 0; i < MapOptions.length; i++) {
            const element = MapOptions[i];
            if (element.layerType == 'background' && element.default == true) {
                BackgroundProvider = element;
            };
            if (element.layerType == 'mark') {
                MarkProvider = element;
            }
        }

        this.ProviderCatch = [];
        BackgroundProvider && this.ProviderCatch.push(BackgroundProvider);
        MarkProvider && this.ProviderCatch.push(MarkProvider);

        BackgroundProvider && this._renderProvider(BackgroundProvider);
        MarkProvider && this._renderProvider(MarkProvider);

        if (!BackgroundProvider && !MarkProvider) {
            this.ProviderCatch.push(MapOptions[0]);
            this._renderProvider(MapOptions[0])
        }
    }

    /**
     * 获取图源列表
     *
     * @return {Array} 当前可显示图源列表
     * @memberof simpleMap
     */
    getProviders() {
        return JSON.parse(JSON.stringify(this.ProviderCatch))
    }
    _renderProvider(option) {
        let viewer = getViewer(this.simpleId);
        let imageryProvider = null;
        if (option.type.toUpperCase() == "ARCGIS") {
            imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
                url: option.url,
                enablePickFeatures: false,
            });
        } else if (option.type.toUpperCase() == "TD") {
            imageryProvider = new Cesium.UrlTemplateImageryProvider({
                url: option.url,
                enablePickFeatures: false,
            });
        } else if (option.type.toUpperCase() == "TMS") {
            imageryProvider = new Cesium.TileMapServiceImageryProvider({
                url: option.url,
                enablePickFeatures: false,
                fileExtension: 'jpg',
            });
        } else {
            throw new Error("imageryProviders中type不存在！");
        }
        if (imageryProvider) {
            viewer.imageryLayers.addImageryProvider(imageryProvider);
        }
    }
    addTerrainProvider(url) {
        let viewer = getViewer(this.simpleId);
        var TerrainProvider = new Cesium.CesiumTerrainProvider({ url: url });
        viewer.terrainProvider = TerrainProvider;
    }
    /**
     * 将地图缩放到中国区域
     *
     * @memberof simpleMap
     */
    flytochina() {
        let viewer = getViewer(this.simpleId);
        viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(101.435314, 37.960521, 10000000.0),
            duration: 2
        });
    }

    /**
     * 自定义缩放位置
     *
     * @param {Object} params 中心点经纬度坐标
     * @memberof simpleMap
     * @example
     * 
     * map.flytoCustom({
     *      longitude : 101.435314,
     *      latitude : 37.960521,
     *      height : 10000000,
     * })
     * 
     */
    flytoCustom(params) {
        let viewer = getViewer(this.simpleId);
        viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(params.longitude, params.latitude, (params.height < 100 ? 100 : params.height)),
            duration: 2
        });
    }

    /**
     * 缩放到指定位置
     *
     * @param {Array} Entitys 对象集合
     * @memberof simpleMap
     */
    viewTo(Entitys) {
        let viewer = getViewer(this.simpleId);
        viewer.flyTo(Entitys, {
            duration: 2
        })
    }


    /**
     * 添加地图自定义图层
     *
     * @param {DataSource} dataSourcesEvent 自定义图层
     * @memberof simpleMap
     */
    addDataSource(DataSource) {
        this.DataSource.push(DataSource);
    }

    /**
     * 删除自定义图层
     *
     * @param {DataSource} dataSourcesEvent 自定义图层
     * @memberof simpleMap
     */
    removeDataSouce(DataSource) {
        let viewer = getViewer(this.simpleId);
        for (let i = 0; i < this.DataSource.length; i++) {
            const element = this.DataSource[i];
            if (DataSource === element) {
                this.DataSource.splice(i, 1)
                viewer.dataSources.remove(element._DataSource);
            }
        }
    }

    /**
     * 获取视图信息
     *
     * @return {Viewer} Cesium 的 Viewer 操作对象
     * @memberof simpleMap
     */
    getViewer() {
        return getViewer(this.simpleId)
    }

    /**
     * 放大地图
     *
     * @memberof simpleMap
     */
    zoomIn() {
        let viewer = getViewer(this.simpleId);
        let height = viewer.camera.positionCartographic.height;
        viewer.camera.zoomIn(height * 0.3);
    }

    /**
     * 缩小地图
     *
     * @memberof simpleMap
     */
    zoomOut() {
        let viewer = getViewer(this.simpleId);
        let height = viewer.camera.positionCartographic.height;
        viewer.camera.zoomOut(height * 0.5);
    }

    /**
     * 注销地图
     *
     * @memberof simpleMap
     */
    destroy() {
        let viewer = getViewer(this.simpleId);
        viewer.clock.onTick.removeEventListener(this._TockEvent);
        viewer.camera.moveEnd.removeEventListener(this._onMoveendMap);
        viewer.destroy();
        this.RightMenu.destroy();
        removeViewer(this.simpleId);
        removeMap(this.simpleId);
        clearInterval(this._onTickTimer);
    }

    /**
     * 经纬度转换
     *
     * @param {Object} Postion 屏幕拾取X，Y 坐标 转换为 地理经纬度坐标
     * @return {Object} 
     * @memberof simpleMap
     */
    formatPostion(Postion) {
        var viewer = getViewer(this.simpleId);
        var event = {};
        let ellipsoid = viewer.scene.globe.ellipsoid;
        var cartographic = ellipsoid.cartesianToCartographic(Postion);
        //经度
        event.latitude = Cesium.Math.toDegrees(cartographic.latitude);
        //纬度
        event.longitude = Cesium.Math.toDegrees(cartographic.longitude);
        //高度
        event.height = viewer.camera.positionCartographic.height / 1000;
        return event;
    }
    _getWindowCoordinates(geometry) {
        var viewer = getViewer(this.simpleId);
        var position = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, Cesium.Cartesian3.fromDegrees(geometry.longitude, geometry.latitude, geometry.height || 0));
        return position;
    }
}



export default simpleMap;